package vcsn;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import vcsn.entities.AddCastingOperation;
import vcsn.entities.AddCommentOperation;
import vcsn.entities.ConflictOperation;
import vcsn.entities.DropInterfaceTypeOperation;
import vcsn.entities.RefineParameterOperation;
import vcsn.entities.RemoveKeyWordOperation;
import vcsn.entities.RenameOperation;

public class ConflictOperationManager {
	 
	public StringBuilder outputBuffer;
	private File processingFile;
	private List<ConflictOperation> conflictOperationList;
	private int currentPositionOfProcess;
	
	public ConflictOperationManager(File processFile, List<ConflictOperation> conflictListInSingleFile){
		outputBuffer = new StringBuilder();
		processingFile = processFile;
		conflictOperationList = conflictListInSingleFile;
		ConflictOperation[] arr = new ConflictOperation[conflictOperationList.size()];
		conflictOperationList.toArray(arr);
		Arrays.sort(arr, 0, arr.length - 1, new Comparator<ConflictOperation>(){

			@Override
			public int compare(ConflictOperation o1, ConflictOperation o2) {
				// TODO Auto-generated method stub
				if(o1.getConflictLocatedPosition() > o2.getConflictLocatedPosition()){
					return 1;
				}else if (o1.getConflictLocatedPosition() < o2.getConflictLocatedPosition()){
					return -1;
				}else{
					return 0;
				}
			}});
		conflictOperationList = new ArrayList<ConflictOperation>();
		for(int i = 0; i < arr.length;i++){
			conflictOperationList.add(arr[i]);
		}
	}
	
	public void execute(){
		try{
		DataInputStream dis = new DataInputStream(new FileInputStream(processingFile));
		
		/*conflictOperationList.get(i);
		while(currentLineOfporcess != conflictOperationList.get(i).getConflictLocatedPosition()){
			
			currentLineOfporcess++;
		}*/
		currentPositionOfProcess = 0;
		int currentLocation = currentPositionOfProcess;
		int bufferIndex = 0;
		byte[] buffer = new byte[Config.bufferSize];
		for(int i = 0; i < conflictOperationList.size();){
			if(currentPositionOfProcess < conflictOperationList.get(i).getConflictLocatedPosition()){
				if(currentLocation < currentPositionOfProcess){
					dis.read();
					currentLocation++;
					continue;
				}
				int b = dis.read();
				if(b == -1){
					break;
				}
				buffer[bufferIndex] = (byte)b;
				bufferIndex++;
				currentPositionOfProcess++;
				currentLocation++;
				continue;
			}else{
				appendToOutputBuffer(buffer, bufferIndex);
				buffer = new byte[Config.bufferSize];
				bufferIndex = 0;
				if(conflictOperationList.get(i) instanceof RenameOperation){
					outputBuffer = ((RenameOperation)conflictOperationList.get(i)).change(outputBuffer);
					if(((RenameOperation)conflictOperationList.get(i)).isOverPosition(currentPositionOfProcess)){
						currentPositionOfProcess += (((RenameOperation)conflictOperationList.get(i)).getOriginIdentifier().length());
					}
				}else if(conflictOperationList.get(i) instanceof AddCommentOperation){
					outputBuffer = ((AddCommentOperation)conflictOperationList.get(i)).change(outputBuffer);
				}else if(conflictOperationList.get(i) instanceof AddCastingOperation){
					outputBuffer = ((AddCastingOperation)conflictOperationList.get(i)).change(outputBuffer);
				}else if(conflictOperationList.get(i) instanceof RemoveKeyWordOperation){
					outputBuffer = ((RemoveKeyWordOperation)conflictOperationList.get(i)).change(outputBuffer);
					currentPositionOfProcess += (((RemoveKeyWordOperation)conflictOperationList.get(i)).getLastParameterEndingPosition() - ((RemoveKeyWordOperation)conflictOperationList.get(i)).getFirstParameterStartingPosition());
				}else if(conflictOperationList.get(i) instanceof DropInterfaceTypeOperation){
					outputBuffer = ((DropInterfaceTypeOperation)conflictOperationList.get(i)).change(outputBuffer);
					currentPositionOfProcess += ((DropInterfaceTypeOperation)conflictOperationList.get(i)).getIdentifierLength();
				}else if(conflictOperationList.get(i) instanceof RefineParameterOperation){
					outputBuffer = ((RefineParameterOperation)conflictOperationList.get(i)).change(outputBuffer);
					currentPositionOfProcess += ((RefineParameterOperation)conflictOperationList.get(i)).getArgumentListLength();
				}
				i++;
			}
		}
		while(currentPositionOfProcess < processingFile.length()){
			if(currentLocation < currentPositionOfProcess){
				dis.read();
				currentLocation++;
				continue;
			}
			int b = dis.read();
			if(b == -1){
				break;
			}
			buffer[bufferIndex] = (byte)b;
			bufferIndex++;
			currentPositionOfProcess++;
			currentLocation++;
		}
		if(bufferIndex > 0){
			appendToOutputBuffer(buffer, bufferIndex);
		}
		dis.close();
		DataOutputStream dataOut = new DataOutputStream(new FileOutputStream(processingFile, false));
		dataOut.writeBytes(outputBuffer.toString());
		dataOut.flush();
		dataOut.close();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}
	
	private void appendToOutputBuffer(byte[] buffer, int bufferIndex){
		if(bufferIndex > 0){
			byte[] byteArr = new byte[bufferIndex + 1];
			for(int i = 0; i <= bufferIndex;i++){
				byteArr[i] = buffer[i];
			}
			try {
				String str = new String(byteArr, Config.charSet);
				outputBuffer.append(str.trim());
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
